package com.guodi.map.controller;

import cn.afterturn.easypoi.csv.CsvImportUtil;
import cn.afterturn.easypoi.csv.entity.CsvImportParams;
import com.guodi.common.constant.StatusCode;
import com.guodi.common.utils.FileUtil;
import com.guodi.core.tool.api.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @描述：地图数据解析控制类
 * @作者：彭辉
 * @日期：2021/8/5 22:14
 */
@RestController
@RequestMapping("/MapDataParsing")
@Api(value = "API - MapDataParsingController", tags = "地图数据解析控制类")
public class MapDataParsingController {

    /**
     * @描述：解析地图坐标点txt文件，上传txt文件，全部视为面，不考虑点线的情况
     * @作者: 陈宏成
     * @日期: 2021-04-13
     */
    @PostMapping("/parseCoordinateTxt")
    @ApiOperation(value = "解析地图坐标点txt文件，上传txt文件，全部视为面，不考虑点线的情况")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "地图坐标点txt文件", required = true,dataType = "file", paramType = "formData"),
    })
    public R parseCoordinateTxt(MultipartFile file) throws IOException, JSONException {
        String originalFilename = file.getOriginalFilename();
        if (!originalFilename.endsWith(".txt")){
            return R.fail(StatusCode.ERROR_CODE_40005,"只能处理.txt后缀的文件");
        }
        // 读取txt文本
        List<String> lineStrList = FileUtil.readLineStr(file.getInputStream());
        if (lineStrList == null || lineStrList.isEmpty()){
            return R.fail(StatusCode.ERROR_CODE_40005,"文本文件的内容为空");
        }
        // 保存坐标点的列表，元素为【x,y】，如果元素是null，则代表换了一个坐标面
        List<JSONArray> pointList = new LinkedList<>();
        // 是否是坐标开始行，只有[地块坐标]的下一行才是坐标面开始行
        boolean isPlaneStart = false;
        // 是否是坐标开始行，只有isPlaneStart == true，同时@符号的下一行才是坐标开始行
        boolean isCoordinateStart = false;
        for(String lineStr : lineStrList) {
            if (!lineStr.contains("地块坐标") && isPlaneStart == false){
                // 说明性文本直接跳过
                isPlaneStart = false;
            }else if (lineStr.contains("地块坐标")){
                // 坐标面开始的标志行
                isPlaneStart = true;
            }else if (isPlaneStart == true && lineStr.contains("@")){
                // 坐标属性的标志行，标识一个面的坐标集开始
                isCoordinateStart = true;
                if (!pointList.isEmpty()){
                    // 如果坐标集合不为空，则加入一个null作为下一个面的分割标志
                    pointList.add(null);
                }
            }else if(isPlaneStart == true && !StringUtils.hasText(lineStr)){
                // 如果没有内容，就说明这个面的坐标到这里就结束了
                isCoordinateStart = false;
            }else if(isPlaneStart == true && isCoordinateStart == true){
                // 坐标行，格式：点号,地块圈号,X坐标,Y坐标
                String[] split = lineStr.split(",");
                try {
                    Double.parseDouble(split[2]);
                    Double.parseDouble(split[3]);
                }catch (NullPointerException | ArrayIndexOutOfBoundsException | NumberFormatException exception){
                    // 如果是不包含,号，或者第3第4为元素不是数字，则说明这一行不是正常的坐标，后面的直接忽略
                    isCoordinateStart = false;
                    isPlaneStart = false;
                    continue;
                }
                JSONArray jsonArray = new JSONArray();
                jsonArray.put(split[2]);
                jsonArray.put(split[3]);
                pointList.add(jsonArray);
            }
        }
        // 整理结果
        if (pointList.isEmpty()){
            return R.data(null);
        }else {
            // 多个点，返回[[[111,222],[333,444]]]
            JSONObject jsonObject = new JSONObject();
            JSONArray jsonArray1 = new JSONArray();
            JSONArray jsonArray2 = new JSONArray();
            jsonArray1.put(jsonArray2);
            jsonObject.put("coordinates",jsonArray1);
            jsonObject.put("type","polygon");
            for(JSONArray point : pointList) {
                if (point == null){
                    jsonArray2 = new JSONArray();
                    jsonArray1.put(jsonArray2);
                    continue;
                }
                jsonArray2.put(point);
            }
            // 遍历jsonArray1，对里面的面进行补充，如果面首尾不是相同的点，就补充一个首坐标点
            for(int i = 0; i < jsonArray1.length(); i++) {
                JSONArray jsonArray = jsonArray1.getJSONArray(i);
                JSONArray firstPoint = jsonArray.getJSONArray(0);
                JSONArray lastPoint = jsonArray.getJSONArray(jsonArray.length() - 1);
                if (!firstPoint.getString(0).equals(lastPoint.getString(0)) || !firstPoint.getString(1).equals(lastPoint.getString(1))){
                    // 如果首尾两个点不同，那就补偿一个首坐标点进去
                    jsonArray.put(firstPoint);
                }
            }
            return R.data(jsonObject.toString());
        }
    }

    /**
     * @描述：解析地图坐标点csv文件
     * @作者: 陈宏成
     * @日期: 2021-04-13
     */
    @PostMapping("/parseCoordinateCsv")
    @ApiOperation(value = "解析地图坐标点csv文件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "地图坐标点csv文件", required = true,dataType = "file", paramType = "formData"),
    })
    public R parseCoordinateCsv(MultipartFile file) throws IOException, JSONException {
        String originalFilename = file.getOriginalFilename();
        if (!originalFilename.endsWith(".csv")){
            return R.fail(StatusCode.ERROR_CODE_40005,"只能处理.csv后缀的文件");
        }
        List<Map> list = CsvImportUtil.importCsv(file.getInputStream(), Map.class, new CsvImportParams());
        if (list == null || list.isEmpty()){
            return R.data(null);
        }else if (list.size() == 1){
            // 只有一个点，返回{x:111,y:222}
            JSONObject jsonObject = new JSONObject();
            Map<String, Object> map = list.get(0);
            Set<Map.Entry<String, Object>> entries = map.entrySet();
            int index = 0;
            for(Map.Entry<String, Object> entry : entries) {
                if (index >= 2){
                    break;
                }
                jsonObject.put(index == 0? "x":"y", entry.getValue());
                index++;
            }
            return R.data(jsonObject.toString());
        }else{
            // 多个点，返回[[[111,222],[333,444]]]
            JSONArray jsonArray1 = new JSONArray();
            JSONArray jsonArray2 = new JSONArray();
            jsonArray1.put(jsonArray2);
            for(Map map : list) {
                JSONArray jsonArray3 = new JSONArray();
                jsonArray2.put(jsonArray3);
                Set<Map.Entry<String, Object>> entries = map.entrySet();
                int index = 0;
                for(Map.Entry<String, Object> entry : entries) {
                    if (index >= 2){
                        break;
                    }
                    jsonArray3.put(entry.getValue());
                    index++;
                }
            }
            JSONObject jsonObject = new JSONObject();
            // 整理返回的数据类型
            if (list.size() == 2){
                // 如果只有两个点，直接当成线
                jsonObject.put("type","polyline");
            }else{
                // 多个点的情况，如果首尾两个点是一样的，那就当成面，否则就是线
                JSONArray firstPoint = jsonArray2.getJSONArray(0);
                JSONArray lastPoint = jsonArray2.getJSONArray(jsonArray2.length() - 1);
                if (firstPoint.getString(0).equals(lastPoint.getString(0)) && firstPoint.getString(1).equals(lastPoint.getString(1))){
                    // 如果首尾两个点是一样的，那就当成面
                    jsonObject.put("type","polygon");
                }else{
                    jsonObject.put("type","polyline");
                }
            }
            jsonObject.put("coordinates",jsonArray1);
            return R.data(jsonObject.toString());
        }
    }
}
